#include "input.h"


#ifdef KEY_DEBUGB
#define dbg_print(fmt, ...)			\
	do{								\
		printk("KEY: ");			\
		printk(fmt, ##__VA_ARGS__);	\
		printk("\r\n");				\
	}while(0)
#else
#define dbg_print(fmt, ...) 
#endif

static int gpio;
static unsigned int irq;
static struct timer_list timer;
static struct input_dev *inputdev;

static irqreturn_t key_handler(int irq, void *dev)
{
	//设置定时器到期时间，如果定时器没有注册则会将其注册
	mod_timer(&timer, jiffies + msecs_to_jiffies(10));

	//返回IRQ_HANDLED，表示中断被成功处理
	return IRQ_HANDLED;
}

static void timer_func(struct timer_list *tm)
{
	//上报GPIO状态
	input_report_key(inputdev, KEY_0, !gpio_get_value(gpio));
	//上报完成
	input_sync(inputdev);
}

static int key_probe(struct platform_device *pled_dev)
{
	int result;
	uint32_t irq_flags;

	printk("**%s probe**\r\n", pled_dev->name);

	//获取GPIO号
	gpio = of_get_named_gpio(pled_dev->dev.of_node, "key-gpio", 0);
	if(gpio < 0)
	{
		dbg_print("get gpio failed\r\n");
		return gpio;
	}
	//申请GPIO
	result = gpio_request(gpio, "key");
	if(result != 0)
	{
		dbg_print("request gpio failed\r\n");
		return result;
	}
	//设置GPIO为输入
	gpio_direction_input(gpio);
	
	//分配输入设备
	inputdev = input_allocate_device();
	if(!inputdev)
	{
		dbg_print("alloc input device failed");
		return -ENOMEM;
	}
	//设置输入设备名称
	inputdev->name = "virtual_input_Device";
	//设置事件类型，按键事件、重复事件
	__set_bit(EV_KEY, inputdev->evbit);
	__set_bit(EV_REP, inputdev->evbit);
	//设置事件码
	__set_bit(KEY_0, inputdev->keybit);
	//注册输入设备
	result = input_register_device(inputdev);
	if(result)
	{
		dbg_print("register input device failed");
		return result;
	}

	//初始化消抖定時器
	timer_setup(&timer, timer_func, 0);

	//获取中断号
	irq = irq_of_parse_and_map(pled_dev->dev.of_node, 0);
	//获取中断触发方式
	irq_flags = irq_get_trigger_type(irq);
	if(irq_flags == IRQF_TRIGGER_NONE)
		irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING;
	//注册中断
	result = request_irq(irq, key_handler, irq_flags, "key", (void*)irq);
	if(result != 0)
	{
		dbg_print("request irq failed\r\n");
		return result;
	}

	return 0;
}

static int key_remove(struct platform_device *pled_dev)
{
	printk("**%s remove**\r\n", pled_dev->name);
	
	//释放中断处理函数
	free_irq(irq, (void*)irq);
	//删除定时器
	del_timer_sync(&timer);
	//注销输入设备
	input_unregister_device(inputdev);
	//释放输入设备
	input_free_device(inputdev);
	//释放GPIO
	gpio_free(gpio);

	return 0;
}

/* 匹配列表，用于设备树和驱动进行匹配 */
static struct of_device_id key_of_match[] = {
	{.compatible = "intr_key"},
	{},
};

static struct platform_driver key_drv = { 
	.driver = {
		.name = "intr_key",
		.of_match_table = key_of_match,
	},
	.probe = key_probe,
	.remove = key_remove,
};


#if 1

static int __init mykey_init(void)
{
	return platform_driver_register(&key_drv);
}

static void __exit mykey_exit(void)
{
	platform_driver_unregister(&key_drv);
}

module_init(mykey_init);
module_exit(mykey_exit);

#else

module_platform_driver(pled_drv);

#endif

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("pinctrl test");
MODULE_ALIAS("pinctrl_led");
